/********************************************************/
/*	Copyright (C) 2016 Gong Li Bin		 	*/
/*	Project:	GoLib-1.0.0			*/
/*	Author:		gong_libin			*/
/*	Date:		2016_01_01			*/
/*	File:		GoCode.go			*/
/********************************************************/

package GoCls

import (
	"unicode"
	"encoding/json"
	"encoding/base32"
	"encoding/base64"
)

// JSON
func GoJsonEncode(v interface{}) ([]byte, error) {
	return json.Marshal(v)
}

func GoJsonDecode(b []byte, v interface{}) error {
	return json.Unmarshal(b, v)
}

// BASE32
const (
	GO_CD_TB32 string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
)

type GoBase32 struct {
	base32 *base32.Encoding
}

func (b *GoBase32) GoBase32New(table string) bool {
	if 0 == len(table) {
		b.base32 = base32.NewEncoding(GO_CD_TB32)
	} else {
		b.base32 = base32.NewEncoding(table)
	}
	return nil != b.base32
}

func (b *GoBase32) GoBase32Encode(src []byte) (dst []byte) {
	dst = make([]byte, (len(src) + 4) / 5 * 8)
	b.base32.Encode(dst, src)
	return dst
}

func (b *GoBase32) GoBase32Decode(src []byte) (dst []byte, num int) {
	dst = make([]byte, len(src))
	num, _ = b.base32.Decode(dst, src)
	return dst, num
}

// BASE64
const (
	GO_CD_TB64 string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
)

type GoBase64 struct {
	base64 *base64.Encoding
}

func (b *GoBase64) GoBase64New(table string) bool {
	if 0 == len(table) {
		b.base64 = base64.NewEncoding(GO_CD_TB64)
	} else {
		b.base64 = base64.NewEncoding(table)
	}
	return nil != b.base64
}

func (b *GoBase64) GoBase64Encode(src []byte) (dst []byte) {
	dst = make([]byte, (len(src) + 2) / 3 * 4)
	b.base64.Encode(dst, src)
	return dst
}

func (b *GoBase64) GoBase64Decode(src []byte) (dst []byte, num int) {
	dst = make([]byte, len(src) / 4 * 3)
	num, _ = b.base64.Decode(dst, src)
	return dst, num
}

// URLENCODE
const (
	GO_CD_CURL string = "0123456789ABCDEF"
)

func __UrlHexInto(b byte) byte {
	return []byte(GO_CD_CURL)[b & 15]
}

func __UrlHexFrom(b byte) byte {
	if true != unicode.IsDigit(rune(b)) {
		r := unicode.ToLower(rune(b))
		return byte(r) - 'a' + 10
	} else {
		return b - '0'
	}
}

func __UrlIsalnum(b byte) bool {
	return ((b | 0x20) - 'a') < 26 || (b - '0') < 10
}

func GoUrlEncode(src []byte) []byte {
	cnt := 0
	dst := make([]byte, len(src) * 3 + 1)
	for _, v := range src {
		if true == __UrlIsalnum(v) || '-' == v || '_' == v || '=' == v || '.' == v || '~' == v {
			dst[cnt] = v
			cnt ++
		} else if ' ' == v {
			dst[cnt] = '+'
			cnt ++
		} else {
			dst[cnt] = '%'
			cnt ++
			dst[cnt] = __UrlHexInto(v >> 4)
			cnt ++
			dst[cnt] = __UrlHexInto(v & 15)
			cnt ++
		}
	}
	return dst
}

func GoUrlDecode(src []byte) []byte {
	cnt := 0
	dst := make([]byte, len(src) + 1)
	for idx := 0; idx < len(src); idx ++ {
		if '%' == src[idx] {
			if 0 != src[idx + 1] && 0 != src[idx + 2] {
				dst[cnt] = __UrlHexFrom(src[idx + 1]) << 4 | __UrlHexFrom(src[idx + 2])
				idx += 2
				cnt += 1
			}
		} else if '+' == src[idx] {
			dst[cnt] = ' '
			cnt += 1
		} else {
			dst[cnt] = src[idx]
			cnt += 1
		}
	}
	return dst
}

// ENCRYPT
const (
	GO_CD_ENCD int = 0x00
	GO_CD_DECD int = 0x01
)

const (
	GO_CD_KEYS string = "1415926535897932384626433832795028841971693993751058209749445923"
)

func GoInfoEncrypt(flag int, key []byte, src []byte) (dst []byte) {
	k := key
	l := len(key)
	s := len(src)
	dst = make([]byte, s)
	if 0 == l {
		k = []byte(GO_CD_KEYS)
		l = len([]byte(GO_CD_KEYS))
	}
	m := s % l
	for i, v := range src {
		switch flag {
			case GO_CD_ENCD:
				dst[i] = v - k[m]
			case GO_CD_DECD:
				dst[i] = v + k[m]
			default:
		}
		m ++
		if m == l {
			m = 0
		}
	}
	return dst
}
